<?php

namespace frame\lib;

use PDO;
use PDOException;

class Db
{
    private static $conn = null;
    protected static $table;
    protected $field = '*';
    protected $where = [];     // 改为数组存储
    protected $whereIn = [];   // 改为数组存储
    protected $order = '';
    protected $likes = [];     // 存储like条件
    protected $limit = '';
    protected $bindParams = []; // 存储所有绑定参数
    protected $bindCount = 0;   // 参数绑定计数器
    public static $query = '';

    public function __construct()
    {
        $this->connect();
    }

    public function connect()
    {
        $config = include ROOT_PATH . 'config' . DS . 'config.php';
        $database = $config['db_database'];
        $username = $config['db_name'];
        $password = $config['db_pass'];
        $dns = "mysql:host=localhost;dbname=$database;charset=utf8mb4";
        try {
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false
            ];
            self::$conn = new PDO($dns, $username, $password, $options);
        } catch (PDOException $e) {
            die("数据库连接失败: " . $e->getMessage());
        }
    }

    public static function name($table)
    {
        $table = self::escapeSQLField($table);
        self::$table = $table;
        return new self();
    }

    public function field($field)
    {
        if (is_array($field)) {
            $field = array_map([self::class, 'escapeSQLField'], $field);
            $this->field = implode(',', $field);
        } else {
            $this->field = $field === '*' ? '*' : self::escapeSQLField($field);
        }
        return $this;
    }

    public function where($param = [])
    {
        foreach ($param as $key => $value) {
            $placeholder = ":where_" . $this->bindCount++;
            $this->where[] = [
                'field' => self::escapeSQLField($key),
                'placeholder' => $placeholder
            ];
            $this->bindParams[$placeholder] = $value;
        }
        return $this;
    }
    public static function query($sql, $params = [], $fetch = true)
    {
        if (self::$conn === null) {
            (new self())->connect();
        }

        try {
            self::$query = $sql; // 保存当前执行的SQL语句
            $stmt = self::$conn->prepare($sql);

            // 绑定参数
            foreach ($params as $key => $value) {
                $type = is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR;
                $stmt->bindValue($key, $value, $type);
            }

            $stmt->execute();

            // 根据查询类型返回不同结果
            if ($fetch) {
                // 如果是SELECT查询，返回结果集
                return $stmt->fetchAll();
            } else {
                // 如果是INSERT/UPDATE/DELETE查询，返回受影响的行数
                return $stmt->rowCount();
            }
        } catch (PDOException $e) {
            error(config('config', 'debug') == true ? $e->getMessage() : '查询执行失败：参数不合法');
            return false;
        }
    }
    public static function queryOne($sql, $params = [])
    {
        $results = self::query($sql, $params);
        return $results ? $results[0] : false;
    }
    public function whereIn($column, $arr = [])
    {
        if (!empty($arr)) {
            $placeholders = [];
            foreach ($arr as $value) {
                $placeholder = ":wherein_" . $this->bindCount++;
                $placeholders[] = $placeholder;
                $this->bindParams[$placeholder] = $value;
            }
            $this->whereIn = [
                'column' => self::escapeSQLField($column),
                'placeholders' => $placeholders
            ];
        }
        return $this;
    }

    public function order($order)
    {
        // 安全处理排序字段和方向
        if (preg_match('/^[a-zA-Z0-9_\.]+(?: (?:ASC|DESC))?$/i', $order)) {
            $this->order = "ORDER BY " . $order;
        }
        return $this;
    }

    /**
     * 支持多个字段的模糊搜索
     * @param string|array $param 当为string时需要配合第二个参数使用，当为array时key为字段名，value为搜索值
     * @param string|null $value 搜索值（当第一个参数为string时使用）
     * @return $this
     */
    public function like($param, $value = null)
    {
        if (is_array($param)) {
            // 数组方式：key为字段，value为搜索值
            foreach ($param as $field => $search) {
                $placeholder = ":like_" . $this->bindCount++;
                $this->likes[] = [
                    'column' => self::escapeSQLField($field),
                    'placeholder' => $placeholder
                ];
                $this->bindParams[$placeholder] = "%{$search}%";
            }
        } else if (is_string($param) && $value !== null) {
            // 传统方式：第一个参数为字段名，第二个参数为搜索值
            $placeholder = ":like_" . $this->bindCount++;
            $this->likes[] = [
                'column' => self::escapeSQLField($param),
                'placeholder' => $placeholder
            ];
            $this->bindParams[$placeholder] = "%{$value}%";
        }
        return $this;
    }

    public function limit($division)
    {
        $page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
        $page = max(1, $page); // 确保页码最小为1
        $division = (int)$division;
        $n = ($page - 1) * $division;

        $placeholder1 = ":limit_" . $this->bindCount++;
        $placeholder2 = ":limit_" . $this->bindCount++;
        $this->limit = "LIMIT {$placeholder1}, {$placeholder2}";
        $this->bindParams[$placeholder1] = $n;
        $this->bindParams[$placeholder2] = $division;

        return $this;
    }

    public function select()
    {
        $sql = "SELECT {$this->field} FROM " . self::$table;
        $conditions = [];

        // 处理WHERE条件
        if (!empty($this->where)) {
            $whereClauses = [];
            foreach ($this->where as $condition) {
                $whereClauses[] = "{$condition['field']} = {$condition['placeholder']}";
            }
            $conditions[] = implode(' AND ', $whereClauses);
        }

        // 处理WHERE IN条件
        if (!empty($this->whereIn)) {
            $placeholders = implode(',', $this->whereIn['placeholders']);
            $conditions[] = "{$this->whereIn['column']} IN ({$placeholders})";
        }

        // 处理LIKE条件
        if (!empty($this->likes)) {
            $likeClauses = [];
            foreach ($this->likes as $like) {
                $likeClauses[] = "{$like['column']} LIKE {$like['placeholder']}";
            }
            $conditions[] = implode(' AND ', $likeClauses);
        }

        // 组合所有条件
        if (!empty($conditions)) {
            $sql .= " WHERE " . implode(' AND ', $conditions);
        }

        // 添加排序和限制
        if (!empty($this->order)) {
            $sql .= " {$this->order}";
        }
        if (!empty($this->limit)) {
            $sql .= " {$this->limit}";
        }

        try {
            $stmt = self::$conn->prepare($sql);
            foreach ($this->bindParams as $key => $value) {
                $stmt->bindValue($key, $value);
            }
            $stmt->execute();
            return $stmt->fetchAll();
        } catch (PDOException $e) {
            error(config('config', 'debug') == true ? $e->getMessage() : '查询失败：参数不合法');
            return false;
        }
    }

    public function find()
    {
        $this->limit(1);
        $result = $this->select();
        return $result ? $result[0] : null;
    }

    public function insert($data)
    {
        $columns = [];
        $placeholders = [];

        foreach ($data as $column => $value) {
            $placeholder = ":insert_" . $this->bindCount++;
            $columns[] = self::escapeSQLField($column);
            $placeholders[] = $placeholder;
            $this->bindParams[$placeholder] = $value;
        }

        $sql = sprintf(
            "INSERT INTO %s (%s) VALUES (%s)",
            self::$table,
            implode(', ', $columns),
            implode(', ', $placeholders)
        );

        return $this->execute($sql);
    }

    public function update($data)
    {
        $setParts = [];
        foreach ($data as $column => $value) {
            $placeholder = ":update_" . $this->bindCount++;
            $setParts[] = self::escapeSQLField($column) . " = " . $placeholder;
            $this->bindParams[$placeholder] = $value;
        }

        $sql = "UPDATE " . self::$table . " SET " . implode(', ', $setParts);

        $conditions = [];
        if (!empty($this->where)) {
            $whereClauses = [];
            foreach ($this->where as $condition) {
                $whereClauses[] = "{$condition['field']} = {$condition['placeholder']}";
            }
            $conditions[] = implode(' AND ', $whereClauses);
        }

        if (!empty($this->whereIn)) {
            $placeholders = implode(',', $this->whereIn['placeholders']);
            $conditions[] = "{$this->whereIn['column']} IN ({$placeholders})";
        }

        if (!empty($conditions)) {
            $sql .= " WHERE " . implode(' AND ', $conditions);
        }

        return $this->execute($sql);
    }

    public function delete($softDelete = true)
    {
        if ($softDelete) {
            return $this->update(['delete_time' => date('Y-m-d H:i:s')]);
        }

        $sql = "DELETE FROM " . self::$table;

        $conditions = [];
        if (!empty($this->where)) {
            $whereClauses = [];
            foreach ($this->where as $condition) {
                $whereClauses[] = "{$condition['field']} = {$condition['placeholder']}";
            }
            $conditions[] = implode(' AND ', $whereClauses);
        }

        if (!empty($this->whereIn)) {
            $placeholders = implode(',', $this->whereIn['placeholders']);
            $conditions[] = "{$this->whereIn['column']} IN ({$placeholders})";
        }

        if (!empty($conditions)) {
            $sql .= " WHERE " . implode(' AND ', $conditions);
        }
        return $this->execute($sql);
    }

    public function count()
    {
        $original_field = $this->field;
        $this->field = 'COUNT(*) as count';
        $result = $this->select();
        $this->field = $original_field;
        return $result ? $result[0]['count'] : 0;
    }

    protected function execute($sql)
    {
        try {
            $stmt = self::$conn->prepare($sql);
            foreach ($this->bindParams as $key => $value) {
                $stmt->bindValue($key, $value);
            }
            $stmt->execute();
            return $stmt->rowCount();
        } catch (PDOException $e) {
            error(config('config', 'debug') == true ? $e->getMessage() : '执行失败：参数不合法');
            return false;
        }
    }

    /**
     * SQL字段名称安全转义
     * @param string $field
     * @return string
     */
    protected static function escapeSQLField($field)
    {
        return '`' . str_replace('`', '', $field) . '`';
    }
}
